home *** CD-ROM | disk | FTP | other *** search
- /*
- File: Except.cpp
-
- Contains: xxx put contents here xxx
-
- Owned by: Ted Jucevic
-
- Copyright: © 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <2> 3/3/96 TJ Added global gVolatile to help make
- ODVolatile realy volatile.
-
- To Do:
- */
-
- /*
- File: Except.cpp
-
- Contains: Exception-handling utility
-
- Owned by: Jens Alfke
-
- Copyright: © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
-
-
- In Progress:
-
- */
-
- #ifndef _PLATFORM_MACINTOSH_
- #define DONT_USE_STACKCRAWL
- #endif
-
- #ifndef __EXCEPT__
- #include "Except.h"
- #endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- #ifndef SOM_Module_OpenDoc_Errors_defined
- #include "ErrorDef.xh"
- #endif
-
- #ifndef _PLFMDEF_
- #include "PlfmDef.h"
- #endif
-
- #ifndef _UTILERRS_
- #include "UtilErrs.h"
- #endif
-
- #ifndef DONT_USE_STACKCRAWL
- #ifndef _CRAWL_
- #include <Crawl.h>
- #endif
- #endif
-
- #ifndef __SOM__
- #include <som.xh>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __STRINGS__
- #include <Strings.h>
- #endif
-
- #ifndef _ODMEMORY_
- #include "ODMemory.h"
- #endif
-
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
-
-
- extern void BREAK( const char[] );
-
-
- static ODBoolean gBreakOnThrow = kODFalse; // Set to true to break on exceptions
-
- void* gVolatile = kODNULL;
-
- const ODSize kSpareMemSize = 512;
- static void* gSpareMem = kODNULL;
- // gSpareMem is a block of memory we keep around to make sure that in an emergency
- // we always have enough memory to allocate a SOM exception, by releasing the spare
- // block if we have to.
-
-
- #pragma segment ODExceptions
-
-
- //=====================================================================================
- // Setting BreakOnThrow
- //=====================================================================================
-
-
- ODBoolean
- BreakOnThrow( ODBoolean brk )
- {
- ODBoolean oldBrk = gBreakOnThrow;
- gBreakOnThrow = brk;
- return oldBrk;
- }
-
-
- //=====================================================================================
- // Initializing ODException Structures
- //=====================================================================================
-
-
- static void
- InitODException( ODException *x, ODError error, const char *message, ODSLong msgsize )
- {
- x->error = error;
- if( message ) {
- ODBlockMove(message,x->message,msgsize);
- x->message[msgsize-1] = '\0';
- } else
- x->message[0] = 0;
- }
-
-
- static ODException*
- NewODException( ODError error, const char *message )
- {
- SOMFree(gSpareMem); // Get some slack
-
- ODULong size = message ?(strlen(message)+1) :1;
- if( size>256 ) size=256;
- ODException *x = (ODException*) SOMMalloc( sizeof(ODError) + size );
-
- if( x )
- InitODException(x,error,message,size);
-
- gSpareMem = SOMMalloc(kSpareMemSize); // Tighten up again
-
- return x;
- }
-
-
- #ifndef _NATIVE_EXCEPTIONS_
-
- //=====================================================================================
- // Stack Maintenance
- //=====================================================================================
-
-
- static ODExceptionFrame *gTopHandler = kODNULL;
-
- inline ODExceptionFrame* GetTopHandler( )
- { return gTopHandler; }
-
-
- //=====================================================================================
- // ODExceptionFrame
- //=====================================================================================
-
-
- #define kAlreadyPoppedHandler ((ODExceptionFrame*)0xDEADBEEF)
-
-
- #ifndef _ASM_XTRY_
- jmp_buf* _xTryEv( ODExceptionFrame *x, Environment *ev )
- {
- if( ! gSpareMem )
- gSpareMem = SOMMalloc(kSpareMemSize);
-
- x->fError = kODNoError;
- x->fODException = kODNULL;
- x->fEv = ev;
- x->fDestructoList = kODNULL;
- x->fPrev = GetTopHandler();
- gTopHandler = x;
- return &x->fBuffer;
- }
-
- jmp_buf* _xTry( ODExceptionFrame *x )
- {
- if( ! gSpareMem )
- gSpareMem = SOMMalloc(kSpareMemSize);
-
- x->fError = kODNoError;
- x->fODException = kODNULL;
- x->fEv = kODNULL;
- x->fDestructoList = kODNULL;
- x->fPrev = GetTopHandler();
- gTopHandler = x;
- return &x->fBuffer;
- }
- #endif /*_ASM_XTRY_*/
-
-
- void _xPop( ODExceptionFrame *x )
- {
- if( GetTopHandler() == x )
- // Remove myself from the stack if (a) I'm at ENDTRY and no exception was thrown,
- // or (b) someone exited (probably via 'return') from within the TRY block:
- gTopHandler = x->fPrev;
-
- else {
- if( x->fPrev == kAlreadyPoppedHandler )
- // Do nothing if I was already popped by a THROW.
- ;
- else {
- /* At this point the astute reader will be wondering how a non-top
- exception handler could be destructed first. Given correct inside-
- out destruction of stack-based objects, this should never happen;
- however, some compilers will mix up the order in certain cases.
- Therefore we roll up our sleeves and prepare to destruct any
- intervening handlers on the stack: */
-
- WARN("Destructing non-top excpt frame %p",x);
-
- ODExceptionFrame *e;
- for( e=gTopHandler; e && e->fPrev!=x; e=e->fPrev )
- ;
- if( e==kODNULL )
- WARN("Excpt frame %p not found on stack!",x);
- else
- e->fPrev = x->fPrev;
- }
-
- /* If exiting a SOM_TRY handler with an error, store it in the Environment: */
- if( x->fEv ) {
- if( x->fODException ) {
- somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
- x->fODException = kODNULL;
- } else if( x->fError )
- ODSetSOMException(x->fEv,x->fError);
- }
- }
-
- if( x->fODException ) {
- SOMFree(x->fODException);
- if( ! gSpareMem )
- gSpareMem = SOMMalloc(kSpareMemSize);
- }
- }
-
-
- void
- ODExceptionFrame::Throw( ODError err, const char* msg, ODException *x )
- {
- if( err == kODNoError ) {
- WARN("Do not call THROW(0)!");
- return;
- }
-
- WASSERT(this==GetTopHandler());
-
- // Call the destructor of each of my destructos:
- for( Destructo *d=fDestructoList; d; d=d->EmergencyDestruct() )
- ;
-
- gTopHandler = fPrev; // Pop the exception handler
- fPrev = kAlreadyPoppedHandler;
-
- // Store error info in this handler. If there's a message, need to copy
- // it into an ODException structure if possible:
- fError = err;
- if( x )
- fODException = x;
- else if( msg && msg[0]!='\0' )
- fODException = NewODException(err,msg);
- else
- fODException = kODNULL;
-
- longjmp(fBuffer,1); // SHAZAM!
- }
-
-
- void
- _xReraise( ODExceptionFrame *xf )
- {
- #if ODDebug
- if( GetTopHandler()==xf )
- BREAK("Reraise called on active exception handler!");
- // Not fatal but probably a mistaken usage of RERAISE.
- #endif
-
- if( xf->fEv ) {
- WARN("RERAISE in SOM_CATCH_ALL block is illegal");
- return;
- }
-
- WASSERTM(xf->fError!=kODNoError,"RERAISE called with no exception");
-
- // Throw the exception, re-using the ODException if possible:
- if( GetTopHandler() ==kODNULL )
- BREAK("No handler to CATCH exception!!");
- else {
- ODException *x = xf->fODException;
- xf->fODException = kODNULL;
- GetTopHandler()->Throw(xf->fError,kODNULL,x);
- }
- }
-
-
- void
- _xSetErrorCode( ODExceptionFrame *xf, ODError err )
- {
- xf->fError = err;
- if( err ) {
- if( xf->fODException )
- xf->fODException->error = err;
- } else {
- SOMFree(xf->fODException);
- xf->fODException = kODNULL;
- }
- }
-
-
- void
- _xSetErrorMessage( ODExceptionFrame *xf, const char *message )
- {
- if( message && message[0]!='\0' ) {
- ODException *x = NewODException(xf->fError,message);
- if( x ) {
- SOMFree(xf->fODException);
- xf->fODException = x;
- }
- } else {
- SOMFree(xf->fODException);
- xf->fODException = kODNULL;
- }
- }
-
-
- //===================================================================================
- // Destructo class
- //===================================================================================
-
-
- #define kIWuzDestructed ((Destructo*)0xDEADBEEF)
- #define kEmergencyDestructing ((Destructo*)0xFADEBABE)
-
-
- Destructo::Destructo( )
- {
- /* Constructor adds me to the current exception frame's destructo list. */
- if( GetTopHandler() ) {
- fPrevDestructo = gTopHandler->fDestructoList;
- gTopHandler->fDestructoList = this;
- } else
- fPrevDestructo = kODNULL;
- }
-
-
- Destructo::~Destructo( )
- {
- /* Destructor removes me from the owner's destructo list, except during
- an emergency destruct while an exception is being thrown; in that case
- the exception handler takes care of that bit itself. */
-
- if( fPrevDestructo != kEmergencyDestructing ) {
- #if ODDebug
- if( fPrevDestructo==kIWuzDestructed ) {
- WARN("Destructo %p being destructed twice!",this);
- return;
- }
- #endif
- if( GetTopHandler() ) {
- if( gTopHandler->fDestructoList == this )
- gTopHandler->fDestructoList = fPrevDestructo;
- else
- WARN("Destructo %p being destructed is not top of list",this);
- }
- }
-
- #if ODDebug
- fPrevDestructo = kIWuzDestructed;
- #endif
- }
-
-
- Destructo*
- Destructo::EmergencyDestruct( )
- {
- /* My owner is _not_ the top handler right now, because it's destructing me in
- a nested TRY block. Jam a special marker into fPrevDestructo to tell my
- destructor not to mess with the Destructo chain; then return the next
- destructo in the chain to help the handler walk it. */
-
- Destructo *prev = fPrevDestructo;
- #if ODDebug
- if( prev==kIWuzDestructed ) {
- WARN("Destructo %p being emergency-destructed twice!",this);
- return kODNULL;
- }
- #endif
-
- fPrevDestructo = kEmergencyDestructing;
- TRY{
- this->~Destructo();
- }CATCH_ALL{
- // Ignore the nested exception.
- }ENDTRY
- return prev;
- }
-
-
- #endif /*not _NATIVE_EXCEPTIONS_*/
-
-
- //===================================================================================
- // THROW, et al
- //===================================================================================
-
-
- static void
- DoThrow( ODError err, const char* msg, ODException *x = kODNULL )
- {
- if( err == kODNoError ) {
- WARN("Do not call THROW(0)!");
- return;
- }
-
- #if ODDebug
- // Dump useful into to stdout or MacsBug. Ignore AE coercion-failure error
- // (-1700 == errAECoercionFail) since it happens as part of normal operation.
-
- if( (GetOutputMode() != kNoOutput || gBreakOnThrow)
- && err!=-1700 && err!=-1708 ) { // Skip noise AE errors
- char caller[256];
- #ifndef DONT_USE_STACKCRAWL
- if( ! ODHaveFreeSpace(1024,1024) )
- strcpy(caller,"??(low mem)??");
- else {
- StackCrawl *sc = StackCrawl::New(2,2);
- sc->GetFrameName(0,caller);
- delete sc;
- }
-
- if( GetOutputMode() != kNoOutput ) {
- if( msg )
- somPrintf("** THROW(%d) called by %s\n", err,caller);
- else
- somPrintf("** THROW(%d,%s) called by %s\n", err,msg,caller);
- if( ODHaveFreeSpace(1024,1024) ) {
- StackCrawl *s = StackCrawl::New(2,-5);
- if( s ) {
- for( long i=0; i<s->CountFrames(); i++ ) {
- char name[256];
- s->GetFrameName(i,name);
- somPrintf(" %s\n",name);
- }
- delete s;
- }
- }
- }
- #else
- strcpy(caller,"????");
- #endif
-
- if( gBreakOnThrow )
- if( msg )
- WARN("THROW(%ld,%s) called by %s", err,msg,caller);
- else
- WARN("THROW(%ld) called by %s", err,caller);
- }
- #endif
-
- #ifdef _NATIVE_EXCEPTIONS_
- ODException x;
- InitODException(&x, err,msg,256);
- throw(x);
- #else
- if( GetTopHandler() ==kODNULL )
- BREAK("No handler to CATCH exception!!");
- else
- GetTopHandler()->Throw(err,msg,x);
- #endif
- }
-
-
-
- void
- THROW( ODError err )
- {
- DoThrow(err,kODNULL);
- }
-
-
- void
- THROW_IF_ERROR( ODError err )
- {
- if( err != 0 )
- DoThrow(err,kODNULL);
- }
-
-
- void
- THROW_IF_NULL( void* value )
- {
- if( value == kODNULL )
- DoThrow(kODErrOutOfMemory,kODNULL);
- }
-
-
- #if ODDebug
- void
- THROW_IF_ERROR_M( ODError err, const char *msg )
- {
- if( err != 0 )
- DoThrow(err,msg);
- }
-
- void
- THROW_M( ODError err, const char* msg )
- {
- DoThrow(err,msg);
- }
-
- void
- THROW_IF_NULL_M( void* value, const char* msg )
- {
- if( value == kODNULL )
- DoThrow(kODErrOutOfMemory,msg);
- }
- #endif /*ODDebug*/
-
-
- //===================================================================================
- // SOM EXCEPTIONS
- //===================================================================================
-
-
- void
- ODSetSOMException( Environment *ev, ODError error, const char *message /*=NULL*/ )
- {
- if( error ) {
- ODException *x = NewODException(error,message);
- SOMFree(gSpareMem); // Get some slack
- somSetException(ev,USER_EXCEPTION,ex_ODException,x);
- gSpareMem = SOMMalloc(kSpareMemSize); // Tighten up
- } else {
- somExceptionFree(ev);
- ev->_major = NO_EXCEPTION;
- }
- }
-
-
- #ifdef _NATIVE_EXCEPTIONS_
- void
- ODSetSOMException( Environment *ev, ODException &except )
- {
- ODSetSOMException(ev,except.error,except.message);
- }
-
- #else
-
- void
- _xSetSOMException( Environment *ev, ODExceptionFrame *x )
- {
- if( !x->fEv ) { // Ignore this in a SOM_TRY block
- if( x->fODException ) {
- SOMFree(gSpareMem); // Get some slack
- somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
- gSpareMem = SOMMalloc(kSpareMemSize); // Tighten up
- x->fODException = kODNULL;
- } else if( x->fError )
- ODSetSOMException(x->fEv,x->fError);
- }
- }
-
- #endif
-
-
- ODError
- ODGetSOMException( Environment *ev )
- {
- if( ev->_major ) {
- const char *excpName = somExceptionId(ev);
- if( strcmp(excpName,ex_ODException) == 0 ) {
- ODException *x = (ODException*)somExceptionValue(ev);
- return x->error;
- } else {
- WARN("Env has non-OpenDoc err: %s",excpName);
- return kODErrSOMException;
- }
- } else
- return kODNoError;
- }
-
-
- void
- CHECK_ENV( Environment *ev )
- {
- if( ev->_major ) {
- const char *excpName = somExceptionId(ev);
- if( strcmp(excpName,ex_ODException) == 0 ) {
- ODException x = *(ODException*)somExceptionValue(ev);
- somExceptionFree(ev);
- ev->_major = NO_EXCEPTION;
- DoThrow(x.error, x.message);
- } else {
- WARN("Env has non-OpenDoc err: %s",excpName);
- somExceptionFree(ev);
- ev->_major = NO_EXCEPTION;
- DoThrow(kODErrSOMException,kODNULL);
- }
- }
- }